#ifndef __MVT_HTTP_WEBSOCKET_H__
#define __MVT_HTTP_WEBSOCKET_H__

#include "mvdef.h"

MVCXX_EXTERN_BEGIN

#include "mvos/mvos_apis.h"
#include "mvt_utilities/mvt_http.h"

typedef enum _websocket_msg_type {
    WSMSG_INVALID = 0,
    WSMSG_TEXT    = 1,
    WSMSG_BIN     = 2,
}mvt_ws_msg_type_e;

typedef mv_ssize_t(*p_on_ws_rejected_f)(mv_vptr_t phdl, mv_s32_t s32_status_code, mv_v8ptr_t pv8_rsp, mv_ssize_t ssz_len);
typedef mv_ssize_t(*p_on_msg_received_f)(mv_vptr_t phdl, mvt_ws_msg_type_e e_msg_type, mv_u8ptr_t pu8_msg, mv_ssize_t ssz_len);

typedef enum _websocket_hdl_status
{
    HDL_INVALID   = 0, ///< 无效
    HDL_READY     = 1, ///< 资源已准备
    HDL_AVAILABLE = 2, ///< 通道可用
    HDL_CLOSE     = 3, ///< 关闭状态
    HDL_TIME_WAIT = 4, ///< 释放前的等待状态
}ws_hdl_status_e;

typedef struct _websocket_handle
{
    /** 初始化数据（需要初始化后，调用new接口） */
    mv_s32_t            s32_com_timeout_ms;       ///< 通信超时时间(毫秒)
    mv_s32_t            s32_keep_alive_interval;  ///< 保活间隔(秒)
    mv_s64_t            s64_msg_max_size;         ///< 接收缓冲区最大大小
    mv_s32_t            s32_reject_msg_max_size;  ///< 拒绝内容缓冲最大限制
    p_on_ws_rejected_f  f_on_ws_rejected;         ///< opening handshake拒绝内容处理回调
    p_on_msg_received_f f_on_msg_received;        ///< 消息处理回调（TEXT和BIN）
    mv_vptr_t           phdl_log;                 ///< (可选)mvt log句柄
    mv_u8_t             u8_log_region;            ///< (可选)mvt log句柄区域
    mv_vptr_t           p_usr_data;               ///< (可选)用户自定义数据
    /** 内部数据（不要修改） */
    mvt_http_t          hdl_http;                 ///< mvt http句柄
    mvos_mutex_t        mutex_send;               ///< 发送接口互斥
    mv_ssize_t          ssz_frame_len;            ///< 帧长度(针对分帧数据接收交换用)
    mv_u8ptr_t          pu8_frame_cache;          ///< 帧缓存(针对分帧数据接收交换用)
    mv_u8_t             u8_frame_type;            ///< 连续分帧类型[mvt_ws_msg_type_e]
    mv_u8_t             u8_status;                ///< 状态标志[ws_hdl_status_e]
    mv_u8_t             u8_snd_ref;               ///< 发送接口过程标志
    mv_u8_t             u8_sdn_dat_ref;           ///< 发送数据帧过程标志
}mvt_ws_hdl_t;

/**
 * @brief 初始化websocket句柄(申请资源)
 * 
 * @param phdl_ws [in] 需要初始化的句柄入口
 * @return 初始化结果
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_INVALID_ARGS (初始化参数异常)
 *           : MV_EC_IGNORE       (重复初始化，忽略操作)
 */
mv_s32_t  mvt_http_ws_new(mvt_ws_hdl_t *phdl_ws);
/**
 * @brief 释放websocket句柄(立即中断连接并释放资源)
 * 
 * @param phdl_ws [in] 需要释放的句柄入口
 * @return 释放结果
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_INVALID_ARGS (初始化参数异常)
 *           : MV_EC_IGNORE       (未初始化，忽略操作)
 */
mv_s32_t  mvt_http_ws_dispose(mvt_ws_hdl_t *phdl_ws);
/**
 * @brief 建立websocket连接(Openning Handshake)
 * 
 * @param phdl_ws       [in] 已初始化的句柄入口
 * @param cpv8_uri      [in] 目标URI
 * @param cpv8_method   [in] 请求方式("GET" / "POST" / ...)，常规标准用"GET"
 * @param cpv8_protocol [in] "Sec-WebSocket-Protocol"，常规普通用"chat"
 * @param pv8_ext_hdrs  [in] 额外协商HTTP请求头(除WS标准外的自定义或特殊请求头，通过此参数追加)，不需要则NULL或""均可
 * @return 连接结果
 * - success : MV_EC_SUCCESS
 * -  failed : else
 * 
 * @note 当前版本封装固定使用version 13的WS
 * 
 * @note 当服务器正常响应连接拒绝时，会通过f_on_ws_rejected传递拒绝内容，应用层自行判断处理方式，并返回对应的返回值，返回值会表现在"连接结果"
 * @note 当服务器由于网络原因没有正常响应时，"连接结果"通常为网络相关错误
 * @note 当连接成功后，尽快安排调用mvt_http_ws_process处理对端信息
 */
mv_s32_t  mvt_http_ws_start(mvt_ws_hdl_t *phdl_ws, mv_cv8ptr_t cpv8_uri, mv_cv8ptr_t cpv8_method, mv_cv8ptr_t cpv8_protocol, mv_v8ptr_t pv8_ext_hdrs);
/**
 * @brief websocket处理过程(接收循环)
 * 
 * @param phdl_ws       [in] 已连接的句柄入口
 * @param pu8_runctrl   [in] 运行控制标记（0=强制退出；1=正常运行）
 * @return 退出码
 * - MV_EC_ABORT : 对端主动关闭（收到CLOSE帧）
 * 
 * @note 此接口为内部循环阻塞实现，故建议调用者根据实际情况创建异步任务进行调用
 */
mv_s32_t mvt_http_ws_process(mvt_ws_hdl_t *phdl_ws, mv_u8ptr_t pu8_runctrl);
/**
 * @brief websocket消息发送
 * 
 * @param phdl_ws       [in] 已连接的句柄入口
 * @param e_msg_type    [in] 消息类型
 * @param cpu8_msg      [in] 消息内容
 * @param s64_len       [in] 消息长度
 * @return 发送结果
 * - success : MV_EC_SUCCESS
 * -  failed : else <0
 */
mv_ssize_t  mvt_http_ws_send_msg(mvt_ws_hdl_t *phdl_ws, mvt_ws_msg_type_e e_msg_type, mv_cu8ptr_t cpu8_msg, mv_ssize_t ssz_len);


#define HTTP_WEBSOCKET_MSG_SIZE   4096

MVCXX_EXTERN_END


#endif

